package com.drg.center.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.drg.center.dao.*;
import com.drg.center.entity.*;
import com.drg.center.entity.param.*;
import com.drg.center.entity.result.*;
import com.drg.center.service.DataMiningAnalysisService;
import com.drg.center.service.StatisticsDoctorFromEsService;
import com.github.javafaker.Faker;
import com.guaike.core.entity.result.PageEntity;
import com.guaike.core.entity.result.Result;
import com.guaike.core.utils.BigDecimalUtil;
import com.guaike.core.utils.ListUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Service
@AllArgsConstructor
public class DataMiningAnalysisServiceImpl implements DataMiningAnalysisService {
    private static final Faker faker = new Faker(new Locale("zh_CN"));
    private final EsDataMiningDAO esDataMiningDAO;
    private final StatisticsDoctorFromEsService statisticsDoctorFromEsService;
    private final DrgPatientCaseOutDAO drgPatientCaseOutDAO;
    private final DrgPatientCasePersonInfoDAO drgPatientCasePersonInfoDAO;
    private final DrgPatientCaseDiagnosisDAO drgPatientCaseDiagnosisDAO;
    private final SysDepartDAO sysDepartDAO;

    private List<String> getSearchMainDepartCodeList(Boolean isMain) {
        if (isMain != null && isMain) {
            return sysDepartDAO.findMainCodeList();
        }
        return null;
    }

    @Override
    public Result<DataQualityVO> dataQualityAnalysis(DataQualityDTO param) {

        List<String> mainSearchDepartCodeList = getSearchMainDepartCodeList(param.getIsMain());

        DataQualityVO vo = new DataQualityVO();
        List<MainDataColumnChartVO> chartVOS = esDataMiningDAO.getProblemDataByYear(param.getDepartCode(), mainSearchDepartCodeList, param.getStartDate(), param.getEndDate());
        vo.setChartItems(chartVOS);
        List<DepartDataStatVO> list = esDataMiningDAO.getProblemDataByDepart(param.getDepartCode(), mainSearchDepartCodeList, param.getStartDate(), param.getEndDate());
        vo.setTableDatas(list);
        return Result.success().data(vo).build();
    }

    @Override
    public Result<MedicalServiceCapabilityVO> medicalServiceCapability(DataQualityDTO param) {
        MedicalServiceCapabilityVO vo = new MedicalServiceCapabilityVO();
        LocalDate start = LocalDate.now();
        LocalDate end = LocalDate.now();
        if (Objects.nonNull(param.getStartDate())) {
            start = param.getStartDate();
        }
        if (Objects.nonNull(param.getEndDate())) {
            end = param.getEndDate();
        }
        List<String> mainSearchDepartCodeList = getSearchMainDepartCodeList(param.getIsMain());
        MedicalServiceOverviewVO overviewVO = esDataMiningDAO.getMedicalServiceOverview(param.getDepartCode(), mainSearchDepartCodeList, start, end);
        BaseCardVO caseCount = new BaseCardVO();
        BaseCardVO oneOrTwoOperationCount = new BaseCardVO();
        BaseCardVO threeOrFourOperationCount = new BaseCardVO();
        BaseCardVO totalPoints = new BaseCardVO();
        BaseCardVO cmi = new BaseCardVO();
        LocalDate startMonth = start.minusMonths(1);
        LocalDate endMonth = end.minusMonths(1);
        MedicalServiceOverviewVO monthVO = esDataMiningDAO.getMedicalServiceOverview(param.getDepartCode(), mainSearchDepartCodeList, startMonth, endMonth);
        caseCount.setTotalData(overviewVO.getCaseCount().toString());
        if (Objects.nonNull(monthVO) && monthVO.getCaseCount() > 0) {
            caseCount.setOnMonth(BigDecimalUtil.formatBigDecimal((new BigDecimal(overviewVO.getCaseCount()).subtract(new BigDecimal(monthVO.getCaseCount()))).divide(new BigDecimal(monthVO.getCaseCount()), 4, BigDecimal.ROUND_HALF_UP).setScale(2, BigDecimal.ROUND_HALF_UP)));
        }
        vo.setCaseCount(caseCount);
        oneOrTwoOperationCount.setTotalData(overviewVO.getOperationLevelOneOrTwoCount().toString());
        if (Objects.nonNull(monthVO) && monthVO.getOperationLevelOneOrTwoCount() > 0) {
            oneOrTwoOperationCount.setOnMonth(BigDecimalUtil.formatBigDecimal((new BigDecimal(overviewVO.getOperationLevelOneOrTwoCount()).subtract(new BigDecimal(monthVO.getOperationLevelOneOrTwoCount()))).divide(new BigDecimal(monthVO.getOperationLevelOneOrTwoCount()), 4, BigDecimal.ROUND_HALF_UP).setScale(2, BigDecimal.ROUND_HALF_UP)));
        }
        vo.setOneOrTwoOperationCount(oneOrTwoOperationCount);
        threeOrFourOperationCount.setTotalData(overviewVO.getOperationLevelThreeOrFourCount().toString());
        if (Objects.nonNull(monthVO) && monthVO.getOperationLevelThreeOrFourCount() > 0) {
            threeOrFourOperationCount.setOnMonth(BigDecimalUtil.formatBigDecimal((new BigDecimal(overviewVO.getOperationLevelThreeOrFourCount()).subtract(new BigDecimal(monthVO.getOperationLevelThreeOrFourCount()))).divide(new BigDecimal(monthVO.getOperationLevelThreeOrFourCount()), 4, BigDecimal.ROUND_HALF_UP).setScale(2, BigDecimal.ROUND_HALF_UP)));
        }
        vo.setThreeOrFourOperationCount(threeOrFourOperationCount);
        totalPoints.setTotalData(overviewVO.getTotalPointCount().toString());
        if (Objects.nonNull(monthVO) && monthVO.getTotalPointCount().compareTo(new BigDecimal(0)) > 0) {
            totalPoints.setOnMonth(BigDecimalUtil.formatBigDecimal((overviewVO.getTotalPointCount().subtract(monthVO.getTotalPointCount())).divide(monthVO.getTotalPointCount(), 4, BigDecimal.ROUND_HALF_UP).setScale(2, BigDecimal.ROUND_HALF_UP)));
        }
        vo.setTotalPoints(totalPoints);
        cmi.setTotalData(randomRate(0, 1.5).toPlainString());
        if (Objects.nonNull(monthVO)) {
            cmi.setOnMonth(randomRate(-20, 50).toPlainString());
        }
        vo.setCmi(cmi);
        DifficultCaseDistributeVO distributeVO = esDataMiningDAO.getDifficultCaseDistribute(param.getDepartCode(), mainSearchDepartCodeList, startMonth, endMonth);
        vo.setCaseDistributeVO(distributeVO);
        List<DepartAngleSttVO> sttVOS = esDataMiningDAO.getMedicalServiceByDept(param.getDepartCode(), mainSearchDepartCodeList, startMonth, endMonth);
        List<DepartCaseProblemVO> problemVOS = ListUtil.copyList(sttVOS, DepartCaseProblemVO.class);
        vo.setDepartCaseProblemVOS(problemVOS);
        return Result.success().data(vo).build();
    }

    @Override
    public Result<DataMedicalServerqualityVO> medicalServiceQuality(@Valid DataQualityDTO param) {
        List<String> mainSearchDepartCodeList = getSearchMainDepartCodeList(param.getIsMain());
        DataMedicalServerqualityVO vo = esDataMiningDAO.getMedicalServerquality(mainSearchDepartCodeList, param.getStartDate(), param.getEndDate());
        return Result.success().data(vo).build();
    }

    @Override
    public Result<List<DepartServiceEfficiencyPageVO>> departServiceEfficiency(DepartServiceEfficiencyDTO param) {
        List<DepartServiceEfficiencyPageVO> list = esDataMiningDAO.getDepartServiceEfficiencyList(param);
        return Result.success().data(list).build();
    }

    @Override
    public void exportDepartServiceEfficiencyExcel(HttpServletResponse response, DepartServiceEfficiencyDTO param) throws Exception {
        List<DepartServiceEfficiencyPageVO> vos = esDataMiningDAO.getDepartServiceEfficiencyList(param);
        List<DepartServiceEfficiencyExcelVO> list = ListUtil.copyList(vos, DepartServiceEfficiencyExcelVO.class);
        OutputStream outputStream = getOutputStream(response, "科室服务效率表格.xlsx");
        EasyExcel.write(outputStream, DepartServiceEfficiencyExcelVO.class)
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                .sheet("科室服务效率")
                .doWrite(list);
    }

    @Override
    public Result<List<DepartDieRatePageVO>> departDieRate(DepartServiceEfficiencyDTO param) {
        List<DepartDieRatePageVO> list = esDataMiningDAO.getDepartDieRateList(param);
        return Result.success().data(list).build();
    }

    @Override
    public void exportDepartDieRateExcel(HttpServletResponse response, DepartServiceEfficiencyDTO param) throws Exception {
        List<DepartDieRatePageVO> vos = esDataMiningDAO.getDepartDieRateList(param);
        List<DepartDieRateExcelVO> list = ListUtil.copyList(vos, DepartDieRateExcelVO.class);
        OutputStream outputStream = getOutputStream(response, "科室死亡率表格.xlsx");
        EasyExcel.write(outputStream, DepartDieRateExcelVO.class)
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                .sheet("科室死亡率")
                .doWrite(list);
    }

    @Override
    public Result<List<MedicareBenchmarkingAnalysisPageVO>> medicalInsuranceBenchmarkingAnalysis(MedicalInsuranceBenchmarkingAnalysisDTO param) {
        List<MedicareBenchmarkingAnalysisPageVO> vos = statisticsDoctorFromEsService.benchmarkStt(param.getChsDrgCode(), param.getInStartDate(), param.getInEndDate());
        return Result.success().data(vos).build();
    }

    @Override
    public void medicalInsuranceBenchmarkingAnalysisExcel(HttpServletResponse response, MedicalInsuranceBenchmarkingAnalysisDTO param) throws Exception {
        List<MedicareBenchmarkingAnalysisPageVO> vos = statisticsDoctorFromEsService.benchmarkStt(param.getChsDrgCode(), param.getInStartDate(), param.getInEndDate());
        List<MedicareBenchmarkingAnalysisExcelVO> list = ListUtil.copyList(vos, MedicareBenchmarkingAnalysisExcelVO.class);
        OutputStream outputStream = getOutputStream(response, "医保标杆值分析表格.xlsx");
        EasyExcel.write(outputStream, MedicareBenchmarkingAnalysisExcelVO.class)
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                .sheet("医保标杆值分析")
                .doWrite(list);
    }

    @Override
    public Result<PatientStructuralAnalysisVO> patientStructuralAnalysis(PatientStructuralAnalysisDTO param) {
        PatientStructuralAnalysisEsVO analysisEsVO = statisticsDoctorFromEsService.structuralStt(param.getSettleStartDate(), param.getSettleEndDate(), param.getStartAge(), param.getEndAge(), param.getCoverage());
        LocalDate start = LocalDate.now();
        LocalDate end = LocalDate.now();
        if (Objects.nonNull(param.getSettleStartDate())) {
            start = param.getSettleStartDate();
        }
        if (Objects.nonNull(param.getSettleEndDate())) {
            end = param.getSettleEndDate();
        }
        LocalDate startMonth = start.minusMonths(1);
        LocalDate endMonth = end.minusMonths(1);
        LocalDate startYear = start.minusYears(1);
        LocalDate endYear = end.minusYears(1);
        PatientStructuralAnalysisVO vo = new PatientStructuralAnalysisVO();
        PatientStructuralAnalysisEsVO analysisEsMonthVO = statisticsDoctorFromEsService.structuralStt(startMonth, endMonth, param.getStartAge(), param.getEndAge(), param.getCoverage());
        PatientStructuralAnalysisEsVO analysisEsYearVO = statisticsDoctorFromEsService.structuralStt(startYear, endYear, param.getStartAge(), param.getEndAge(), param.getCoverage());
        BaseCardVO caseCount = new BaseCardVO();
        caseCount.setTotalData(analysisEsVO.getCaseCount().toString());
        if (Objects.nonNull(analysisEsMonthVO) && analysisEsMonthVO.getCaseCount() > 0) {
            caseCount.setOnMonth(BigDecimalUtil.formatBigDecimal((new BigDecimal(analysisEsVO.getCaseCount()).subtract(new BigDecimal(analysisEsMonthVO.getCaseCount()))).divide(new BigDecimal(analysisEsMonthVO.getCaseCount()), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)));
        }
        if (Objects.nonNull(analysisEsYearVO) && analysisEsYearVO.getCaseCount() > 0) {
            caseCount.setOnYear(BigDecimalUtil.formatBigDecimal((new BigDecimal(analysisEsVO.getCaseCount()).subtract(new BigDecimal(analysisEsYearVO.getCaseCount()))).divide(new BigDecimal(analysisEsYearVO.getCaseCount()), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)));
        }
        vo.setCaseCount(caseCount);
        BaseCardVO diseaseGroup = new BaseCardVO();
        diseaseGroup.setTotalData(analysisEsVO.getDiseaseGroup().toString());
        if (Objects.nonNull(analysisEsMonthVO) && analysisEsMonthVO.getDiseaseGroup() > 0) {
            diseaseGroup.setOnMonth(BigDecimalUtil.formatBigDecimal((new BigDecimal(analysisEsVO.getDiseaseGroup()).subtract(new BigDecimal(analysisEsMonthVO.getDiseaseGroup()))).divide(new BigDecimal(analysisEsMonthVO.getDiseaseGroup()), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)));
        }
        if (Objects.nonNull(analysisEsYearVO) && analysisEsYearVO.getDiseaseGroup() > 0) {
            diseaseGroup.setOnYear(BigDecimalUtil.formatBigDecimal((new BigDecimal(analysisEsVO.getDiseaseGroup()).subtract(new BigDecimal(analysisEsYearVO.getDiseaseGroup()))).divide(new BigDecimal(analysisEsYearVO.getDiseaseGroup()), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)));
        }
        vo.setDiseaseGroup(diseaseGroup);
        BaseCardVO totalTreatCost = new BaseCardVO();
        totalTreatCost.setTotalData(analysisEsVO.getTotalTreatCost().toPlainString());
        if (Objects.nonNull(analysisEsMonthVO) && analysisEsMonthVO.getTotalTreatCost().doubleValue() > 0) {
            totalTreatCost.setOnMonth(BigDecimalUtil.formatBigDecimal((analysisEsVO.getTotalTreatCost().subtract(analysisEsMonthVO.getTotalTreatCost())).divide(analysisEsMonthVO.getTotalTreatCost(), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)));
        }
        if (Objects.nonNull(analysisEsYearVO) && analysisEsYearVO.getTotalTreatCost().doubleValue() > 0) {
            totalTreatCost.setOnYear(BigDecimalUtil.formatBigDecimal((analysisEsVO.getTotalTreatCost().subtract(analysisEsYearVO.getTotalTreatCost())).divide(analysisEsYearVO.getTotalTreatCost(), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)));
        }
        vo.setTotalTreatCost(totalTreatCost);
        BaseCardVO avgCost = new BaseCardVO();
        avgCost.setTotalData(analysisEsVO.getAvgCost().toPlainString());
        if (Objects.nonNull(analysisEsMonthVO) && analysisEsMonthVO.getAvgCost().doubleValue() > 0) {
            avgCost.setOnMonth(BigDecimalUtil.formatBigDecimal((analysisEsVO.getAvgCost().subtract(analysisEsMonthVO.getAvgCost())).divide(analysisEsMonthVO.getAvgCost(), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)));
        }
        if (Objects.nonNull(analysisEsYearVO) && analysisEsYearVO.getAvgCost().doubleValue() > 0) {
            avgCost.setOnYear(BigDecimalUtil.formatBigDecimal((analysisEsVO.getAvgCost().subtract(analysisEsYearVO.getAvgCost())).divide(analysisEsYearVO.getAvgCost(), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)));
        }
        vo.setAvgCost(avgCost);
        BaseCardVO medicineCost = new BaseCardVO();
        medicineCost.setTotalData(analysisEsVO.getMedicineCost().toPlainString());
        if (Objects.nonNull(analysisEsMonthVO) && analysisEsMonthVO.getMedicineCost().doubleValue() > 0) {
            medicineCost.setOnMonth(BigDecimalUtil.formatBigDecimal((analysisEsVO.getMedicineCost().subtract(analysisEsMonthVO.getMedicineCost())).divide(analysisEsMonthVO.getMedicineCost(), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)));
        }
        if (Objects.nonNull(analysisEsYearVO) && analysisEsYearVO.getMedicineCost().doubleValue() > 0) {
            medicineCost.setOnYear(BigDecimalUtil.formatBigDecimal((analysisEsVO.getMedicineCost().subtract(analysisEsYearVO.getMedicineCost())).divide(analysisEsYearVO.getMedicineCost(), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)));
        }
        vo.setMedicineCost(medicineCost);
        BaseCardVO medicineAvgCost = new BaseCardVO();
        medicineAvgCost.setTotalData(analysisEsVO.getMedicineAvgCost().toPlainString());
        if (Objects.nonNull(analysisEsMonthVO) && analysisEsMonthVO.getMedicineAvgCost().doubleValue() > 0) {
            medicineAvgCost.setOnMonth(BigDecimalUtil.formatBigDecimal((analysisEsVO.getMedicineAvgCost().subtract(analysisEsMonthVO.getMedicineAvgCost())).divide(analysisEsMonthVO.getMedicineAvgCost(), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)));
        }
        if (Objects.nonNull(analysisEsYearVO) && analysisEsYearVO.getMedicineAvgCost().doubleValue() > 0) {
            medicineAvgCost.setOnYear(BigDecimalUtil.formatBigDecimal((analysisEsVO.getMedicineAvgCost().subtract(analysisEsYearVO.getMedicineAvgCost())).divide(analysisEsYearVO.getMedicineAvgCost(), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)));
        }
        vo.setMedicineAvgCost(medicineAvgCost);
        BaseCardVO consumablesCost = new BaseCardVO();
        consumablesCost.setTotalData(analysisEsVO.getConsumablesCost().toPlainString());
        if (Objects.nonNull(analysisEsMonthVO) && analysisEsMonthVO.getConsumablesCost().doubleValue() > 0) {
            consumablesCost.setOnMonth(BigDecimalUtil.formatBigDecimal((analysisEsVO.getConsumablesCost().subtract(analysisEsMonthVO.getConsumablesCost())).divide(analysisEsMonthVO.getConsumablesCost(), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)));
        }
        if (Objects.nonNull(analysisEsYearVO) && analysisEsYearVO.getConsumablesCost().doubleValue() > 0) {
            consumablesCost.setOnYear(BigDecimalUtil.formatBigDecimal((analysisEsVO.getConsumablesCost().subtract(analysisEsYearVO.getConsumablesCost())).divide(analysisEsYearVO.getConsumablesCost(), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)));
        }
        vo.setConsumablesCost(consumablesCost);
        BaseCardVO consumablesAvgCost = new BaseCardVO();
        consumablesAvgCost.setTotalData(analysisEsVO.getConsumablesAvgCost().toPlainString());
        if (Objects.nonNull(analysisEsMonthVO) && analysisEsMonthVO.getConsumablesAvgCost().doubleValue() > 0) {
            consumablesAvgCost.setOnMonth(BigDecimalUtil.formatBigDecimal((analysisEsVO.getConsumablesAvgCost().subtract(analysisEsMonthVO.getConsumablesAvgCost())).divide(analysisEsMonthVO.getConsumablesAvgCost(), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)));
        }
        if (Objects.nonNull(analysisEsYearVO) && analysisEsYearVO.getConsumablesAvgCost().doubleValue() > 0) {
            consumablesAvgCost.setOnYear(BigDecimalUtil.formatBigDecimal((analysisEsVO.getConsumablesAvgCost().subtract(analysisEsYearVO.getConsumablesAvgCost())).divide(analysisEsYearVO.getConsumablesAvgCost(), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)));
        }
        vo.setConsumablesAvgCost(consumablesAvgCost);
        BaseCardVO otherCost = new BaseCardVO();
        otherCost.setTotalData(analysisEsVO.getOtherCost().toPlainString());
        if (Objects.nonNull(analysisEsMonthVO) && analysisEsMonthVO.getOtherCost().doubleValue() > 0) {
            otherCost.setOnMonth(BigDecimalUtil.formatBigDecimal((analysisEsVO.getOtherCost().subtract(analysisEsMonthVO.getOtherCost())).divide(analysisEsMonthVO.getOtherCost(), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)));
        }
        if (Objects.nonNull(analysisEsYearVO) && analysisEsYearVO.getOtherCost().doubleValue() > 0) {
            otherCost.setOnYear(BigDecimalUtil.formatBigDecimal((analysisEsVO.getOtherCost().subtract(analysisEsYearVO.getOtherCost())).divide(analysisEsYearVO.getOtherCost(), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)));
        }
        vo.setOtherCost(otherCost);
        BaseCardVO otherAvgCost = new BaseCardVO();
        otherAvgCost.setTotalData(analysisEsVO.getOtherAvgCost().toPlainString());
        if (Objects.nonNull(analysisEsMonthVO) && analysisEsMonthVO.getOtherAvgCost().doubleValue() > 0) {
            otherAvgCost.setOnMonth(BigDecimalUtil.formatBigDecimal((analysisEsVO.getOtherAvgCost().subtract(analysisEsMonthVO.getOtherAvgCost())).divide(analysisEsMonthVO.getOtherAvgCost(), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)));
        }
        if (Objects.nonNull(analysisEsYearVO) && analysisEsYearVO.getOtherAvgCost().doubleValue() > 0) {
            otherAvgCost.setOnYear(BigDecimalUtil.formatBigDecimal((analysisEsVO.getOtherAvgCost().subtract(analysisEsYearVO.getOtherAvgCost())).divide(analysisEsYearVO.getOtherAvgCost(), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)));
        }
        vo.setOtherAvgCost(otherAvgCost);
        return Result.success().data(vo).build();
    }

    @Override
    public Result<PageEntity<PatientAccessCostsAnalysisPageVO>> patientAccessCostsAnalysis(PatientAccessCostsAnalysisDTO param) {
        Page<DrgPatientCaseOutPO> poPage = drgPatientCaseOutDAO.patientAccessCostsAnalysis(param);
        PageEntity<PatientAccessCostsAnalysisPageVO> result = new PageEntity<>();
        List<PatientAccessCostsAnalysisPageVO> list = new ArrayList<>();
        poPage.getRecords().forEach(po -> {
            PatientAccessCostsAnalysisPageVO vo = new PatientAccessCostsAnalysisPageVO();
            vo.setInpatientCode(po.getInpatientCode());
            DrgPatientCasePersonInfoPO infoPO = drgPatientCasePersonInfoDAO.findOne(DrgPatientCasePersonInfoPO::getCaseCode, po.getCaseCode());
            vo.setPatientName(infoPO.getPatientName());
            vo.setTotalCost(po.getTotalCost());
            vo.setDepartName(po.getDepartName());
            vo.setMedicareReimbursementAmount(po.getReimburseCost());
            vo.setOutOfPocketAmount(po.getSelfCost());
            list.add(vo);
        });
        result.setTotal(poPage.getTotal());
        result.setList(list);
        return Result.success().data(result).build();
    }

    @Override
    public void patientAccessCostsAnalysisExcel(HttpServletResponse response, PatientAccessCostsAnalysisDTO param) throws Exception {

    }

    @Override
    public Result<List<ComprehensiveAnalysisPageVO>> comprehensiveAnalysis(ComprehensiveAnalysisDTO param) {
        List<ComprehensiveAnalysisPageVO> vos = statisticsDoctorFromEsService.comprehensiveStt(param.getDepartCode(), param.getSettleStartDate(), param.getSettleEndDate());
        return Result.success().data(vos).build();
    }

    @Override
    public void comprehensiveAnalysisExcel(HttpServletResponse response, ComprehensiveAnalysisDTO param) throws Exception {

    }

    @Override
    public Result<List<OverRankingAnalysisPageVO>> overRankingAnalysis(OverRankingAnalysisDTO param) {
        List<OverRankingAnalysisPageVO> vos = statisticsDoctorFromEsService.overRankStt(param.getStartDate(), param.getEndDate());
        return Result.success().data(vos).build();
    }

    @Override
    public void overRankingAnalysisExcel(HttpServletResponse response, OverRankingAnalysisDTO param) throws Exception {

    }

    @Override
    public Result<PageEntity<AuditResultsAnalysisPageVO>> auditResultsAnalysis(AuditResultsAnalysisDTO param) {
        PageEntity<AuditResultsAnalysisPageVO> result = new PageEntity<>();
        List<AuditResultsAnalysisPageVO> list = new ArrayList<>();
        Page<DrgPatientCaseOutPO> poPage = drgPatientCaseOutDAO.auditResultsAnalysis(param);
        poPage.getRecords().forEach(po -> {
            AuditResultsAnalysisPageVO vo = new AuditResultsAnalysisPageVO();
            vo.setInpatientCode(po.getInpatientCode());
            DrgPatientCasePersonInfoPO infoPO = drgPatientCasePersonInfoDAO.findOne(DrgPatientCasePersonInfoPO::getCaseCode, po.getCaseCode());
            vo.setPatientName(infoPO.getPatientName());
            vo.setAge(infoPO.getPatientAge());
            vo.setAgeDay(infoPO.getAgeDay());
            vo.setSex(infoPO.getPatientSex());
            vo.setMedicareType(infoPO.getMedicareType());
            List<DrgPatientCaseDiagnosisPO> diagnosisPOS = drgPatientCaseDiagnosisDAO.findMainList(po.getCaseCode());
            List<String> collect = diagnosisPOS.stream().map(DrgPatientCaseDiagnosisPO::getDiagnosisName).collect(Collectors.toList());
            vo.setDiagnosisList(collect);
            vo.setType(po.getMedicalType());
            vo.setMonitorType(faker.options().option("自费支付", "符合使用条件，医保支付"));
            list.add(vo);
        });
        result.setList(list);
        result.setTotal(poPage.getTotal());
        return Result.success().data(result).build();
    }

    @Override
    public Result<PageEntity<SingleDiseaseHospitalizationCostAnalysisPageVO>> singleDiseaseHospitalizationCostAnalysis(SingleDiseaseHospitalizationCostAnalysisDTO param) {
        PageEntity<SingleDiseaseHospitalizationCostAnalysisPageVO> result = new PageEntity<>();
        List<SingleDiseaseHospitalizationCostAnalysisPageVO> list = new ArrayList<>();
        Page<DrgPatientCaseOutPO> poPage = drgPatientCaseOutDAO.singleDiseaseHospitalizationCostAnalysis(param);
        poPage.getRecords().forEach(po -> {
            SingleDiseaseHospitalizationCostAnalysisPageVO vo = new SingleDiseaseHospitalizationCostAnalysisPageVO();
            vo.setDepartName(po.getDepartName());
            vo.setDoctorName(po.getDoctorName());
            DrgPatientCasePersonInfoPO infoPO = drgPatientCasePersonInfoDAO.findOne(DrgPatientCasePersonInfoPO::getCaseCode, po.getCaseCode());
            vo.setPatientName(infoPO.getPatientName());
            List<DrgPatientCaseDiagnosisPO> diagnosisPOS = drgPatientCaseDiagnosisDAO.findMainList(po.getCaseCode());
            List<String> collect = diagnosisPOS.stream().map(DrgPatientCaseDiagnosisPO::getDiagnosisName).collect(Collectors.toList());
            vo.setDiagnosisList(collect);
            vo.setTotalCost(po.getTotalCost());
            vo.setStartDate(po.getInHospitalDate().toLocalDate());
            vo.setEndDate(po.getOutHospitalDate().toLocalDate());
            vo.setInpatientDays(po.getInpatientDays());
            list.add(vo);
        });
        result.setList(list);
        result.setTotal(poPage.getTotal());
        return Result.success().data(result).build();
    }

    /**
     * 导出时生成OutputStream
     */
    private static OutputStream getOutputStream(HttpServletResponse response, String fileName) throws Exception {
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName);
        return response.getOutputStream();
    }

    private static BigDecimal randomRate(double min, double max) {
        return BigDecimal.valueOf(RandomUtil.randomDouble(min, max, 2, RoundingMode.HALF_UP));
    }
}
